﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;

namespace mySnake
{
    // 游戏状态
    public enum GAME_STATUS
    {
        GAME_STATUS_RUNNING, GAME_STATUS_PAUSED, GAME_STATUS_FINISH,
    }

    // 移动方向
    public enum GAME_DIRECTION
    {
        GAME_DIRECTION_UP, GAME_DIRECTION_DOWN, GAME_DIRECTION_LEFT, GAME_DIRECTION_RIGHT,
    }

    // 游戏速度，定时器触发一次10ms
    public enum GAME_SPEED
    {
        GAME_SPEED_LOWER = 30, GAME_SPEED_NORMAL = 20, GAME_SPEED_MEDIUM = 10, GAME_SPEED_HARD = 7,
    }

    // 游戏参数
    public class GameParam
    {
        // 方块列数
        public int Cols { get; set; }
        // 方块行数
        public int Rows { get; set; }
        // 方块大小
        public int BlockWidth { get; set; }

        // 游戏状态
        public GAME_STATUS GameStatus { get; set; }
        // 游戏速度
        public GAME_SPEED GameSpeed { get; set; }
        // 按键方向
        public GAME_DIRECTION KeyDirection { get; set; }
        // 实际移动方向
        public GAME_DIRECTION MoveDirection { get; set; }

        // snake身体节点
        public List<SnakeNode> snake;

        // 得分节点
        public SnakeNode scoreNode;

        // 定时器计数次数，控制移动速度,定时器触发一次10ms
        public int SpeedCounter { get; set; }

        // 游戏得分
        public int GameScore { get; set; }

        // 得分事件
        public event EventHandler ScoreEvent;
        public class ScoreEventArgs : EventArgs
        {
            public int Score { get; set; }
        }

        // 游戏状态改变事件
        public event EventHandler GameStatusChangeEvent;
        public class GameStatusEventArgs : EventArgs
        {
            public GAME_STATUS GameStatus { get; set; }
        }

        public GameParam()
        {
            Cols = 38;
            Rows = 21;
            BlockWidth = 20;
        }

        public void InitSnake()
        {
            GameStatus = GAME_STATUS.GAME_STATUS_PAUSED;
            KeyDirection = GAME_DIRECTION.GAME_DIRECTION_RIGHT;
            MoveDirection = GAME_DIRECTION.GAME_DIRECTION_RIGHT;
            GameSpeed = GAME_SPEED.GAME_SPEED_LOWER;
            SpeedCounter = 0;

            snake = new List<SnakeNode>();
            scoreNode = new SnakeNode();

            // 初始snake身体节点
            for (int i = 10; i < 13; i++)
            {
                SnakeNode snakeNode = new SnakeNode();
                snakeNode.Row = 7;
                snakeNode.Col = i;
                snakeNode.Color = Color.Red;
                snakeNode.BlockWidth = BlockWidth;
                snake.Add(snakeNode);
            }

            // 初始得分节点
            GenScoreNodePosition();
        }

        // 根据移动方向生成snake身体节点，并判断是否得分和游戏失败
        public void GenMoveSnake()
        {
            GAME_DIRECTION curDirection = MoveDirection;
            SnakeNode head = snake.Last<SnakeNode>();
            int curRow = head.Row;
            int curCol = head.Col;
            SnakeNode newNode = new SnakeNode();

            if (curDirection == GAME_DIRECTION.GAME_DIRECTION_UP && KeyDirection != GAME_DIRECTION.GAME_DIRECTION_DOWN)
            {
                MoveDirection = KeyDirection;
            }
            else if (curDirection == GAME_DIRECTION.GAME_DIRECTION_DOWN && KeyDirection != GAME_DIRECTION.GAME_DIRECTION_UP)
            {
                MoveDirection = KeyDirection;
            }
            else if (curDirection == GAME_DIRECTION.GAME_DIRECTION_LEFT && KeyDirection != GAME_DIRECTION.GAME_DIRECTION_RIGHT)
            {
                MoveDirection = KeyDirection;
            }
            else if (curDirection == GAME_DIRECTION.GAME_DIRECTION_RIGHT && KeyDirection != GAME_DIRECTION.GAME_DIRECTION_LEFT)
            {
                MoveDirection = KeyDirection;
            }

            switch (MoveDirection)
            {
                case GAME_DIRECTION.GAME_DIRECTION_LEFT:
                    {
                        curCol -= 1;
                    }
                    break;
                case GAME_DIRECTION.GAME_DIRECTION_RIGHT:
                    {
                        curCol += 1;
                    }
                    break;
                case GAME_DIRECTION.GAME_DIRECTION_DOWN:
                    {
                        curRow += 1;
                    }
                    break;
                case GAME_DIRECTION.GAME_DIRECTION_UP:
                    {
                        curRow -= 1;
                    }
                    break;
            }

            if (JudgeGameFail(curRow, curCol, snake))
            {
                GameStatus = GAME_STATUS.GAME_STATUS_FINISH;

                GameStatusEventArgs e = new GameStatusEventArgs();
                e.GameStatus = GAME_STATUS.GAME_STATUS_FINISH;
                // 游戏状态改变事件触发
                GameStatusChangeEvent.BeginInvoke(this, e, null, null);
                return;
            }

            newNode.Row = curRow;
            newNode.Col = curCol;
            newNode.BlockWidth = BlockWidth;
            newNode.Color = Color.Red;

            if (!JudgeEatScore(curRow, curCol, scoreNode))
            {
                snake.RemoveAt(0);
            }
            else
            {
                GameScore++;
                GenScoreNodePosition();
                ScoreEventArgs args = new ScoreEventArgs();
                args.Score = GameScore;
                // 得分事件触发
                ScoreEvent.BeginInvoke(this, args, null, null);
            }
            snake.Add(newNode);
        }

        // 生成得分节点
        public int GenScoreNodePosition()
        {
            Random r = new Random();
            int row = r.Next(1, Rows + 1);
            int col = r.Next(1, Cols + 1);

            scoreNode.Row = row;
            scoreNode.Col = col;
            scoreNode.Color = Color.Yellow;
            scoreNode.BlockWidth = BlockWidth;

            return 0;
        }

        // 判断是否得分
        public bool JudgeEatScore(int row, int col, SnakeNode score) => score.Row == row && score.Col == col;

        // 判断游戏是否失败
        public bool JudgeGameFail(int row, int col, List<SnakeNode> snake)
        {
            if (row == 0 || col == 0 || row == Rows + 1 || col == Cols + 1)
            {
                return true;
            }
            return false;
        }

        // GameParam参数构建器
        public class Builder
        {
            GameParam gameParam;
            public Builder()
            {
                gameParam = new GameParam();
            }

            public Builder setCols(int cols)
            {
                gameParam.Cols = cols;
                return this;
            }

            public Builder setRows(int rows)
            {
                gameParam.Rows = rows;
                return this;
            }

            public Builder setBlockWidth(int w)
            {
                gameParam.BlockWidth = w;
                return this;
            }

            public GameParam build()
            {
                return gameParam;
            }
        }
    }

}
